﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace KaartenLib
{
    public delegate void LegeLijstEventHandler(object sender, EventArgs e);

    public class LegeLijstEvent : EventArgs
    {
        internal string zin;
        public LegeLijstEvent(string zin) : base()
        {
            this.zin = zin;
        }

        public override string ToString()
        {
            return zin;
        }
    }


    public class KaartSpel : ICloneable, IEnumerable<Kaart>
    {
        List<Kaart> kaarten = new List<Kaart>();
        private Random random = new Random();
        public event LegeLijstEventHandler LegeLijst;

        public KaartSpel()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 1; j < 14; j++)
                {
                    VoegKaartToe(new Kaart((KaartSoort)i, (KaartWaarde)j));
                }
            }
        }

        public KaartSpel(ICollection<Kaart> col)
        {
            VoegKaartenToe(col);
        }

        public List<Kaart> Kaarten
        {
            get
            {
                return kaarten;
            }
            set
            {
                kaarten = value;
            }
        }

        public int AantalKaarten()
        {
            return kaarten.Count;
        }

        public virtual void VoegKaartToe(Kaart kaart)
        {
            if (kaarten != null)
            {
                if (!kaarten.Contains(kaart))
                {
                    kaarten.Add(kaart);

                }
                else
                {
                    throw new InvalidOperationException("Er is al reeds een kaart in het spel dezelfde waarde en soort hebben!");
                }
            }
            else
            {
                throw new InvalidOperationException("Er bestaat nog geen lijst met kaarten!");
            }
        }

        public void VoegKaartenToe(ICollection<Kaart> kaarten)
        {
            foreach (Kaart k in kaarten)
            {
                VoegKaartToe(k);
            }
        }

        public Kaart TrekRandomKaart()
        {
            int i = random.Next(kaarten.Count);
            return TrekKaart(i);
        }

        public Kaart TrekBovensteKaart()
        {
            int i = this.AantalKaarten() - 1;
            return TrekKaart(i);
        }

        public Kaart TrekKaart(int index)
        {
            if (index >= 0 && index < AantalKaarten())
            {
                Kaart kaart = kaarten[index];
                kaarten.Remove(kaart);
                if (kaarten.Count == 0)
                {
                    OnChange(EventArgs.Empty);
                }
                else
                {
                    bool lastSort = true;
                    foreach (var k in kaarten)
                    {
                        if (k.Soort == kaart.Soort)
                        {
                            lastSort = false;
                        }
                    }
                    if (lastSort)
                    {
                        OnChange(new LegeLijstEvent("Kaarten van de soort " + kaart.Soort + " zijn op."));
                    }
                }
                return kaart;
            }
            else
            {
                throw new ArgumentOutOfRangeException("index", index, "index moet liggen tussen 0 en " + (AantalKaarten() - 1));
            }
        }

        protected virtual void OnChange(EventArgs e)
        {
            if (LegeLijst != null)
            {
                LegeLijst(this, e);
            }
        }

        
        public void Schudden()
        {
            List<Kaart> nieuweKaarten = new List<Kaart>();
            while (kaarten.Count > 0)
            {
                int hulpKaart = random.Next(kaarten.Count);
                nieuweKaarten.Add(kaarten[hulpKaart]);
                kaarten.RemoveAt(hulpKaart);
            }
            kaarten = nieuweKaarten;
        }

        //•	Kaartspel moet (deep) cloneable zijn
        public Kaart ZoekKaart(int index)
        {
            return this[index];
        }

        public Kaart ZoekKaart(KaartWaarde waarde, KaartSoort soort)
        {
            foreach (Kaart k in kaarten)
            {
                if (k.Soort == soort && k.Waarde == waarde)
                {
                    return k;
                }
            }
            return null;
        }

        public void SorteerKaarten()
        {
            kaarten.Sort();
        }

        public void SorteerKaarten(KaartSoort[] volgorde)
        {
            kaarten.Sort(new KaartenComparerMetEigenVolgorde(volgorde));
        }

        public class KaartenComparerTypesEnWaarden : IComparer<Kaart>
        {
            public int Compare(Kaart x, Kaart y)
            {
                if (x.Soort > y.Soort) return 1;
                if (x.Soort < y.Soort) return -1;
                if (x.Waarde > y.Waarde) return 1;
                if (x.Waarde < y.Waarde) return -1;
                return 0;
            }
        }

        public class KaartenComparerMetEigenVolgorde : IComparer<Kaart>
        {
            private KaartSoort[] volgorde;
            public KaartenComparerMetEigenVolgorde(KaartSoort[] volgorde)
            {
                this.volgorde = volgorde;
            }

            public int Compare(Kaart x, Kaart y)
            {
                if (Array.IndexOf(volgorde, x.Soort) > Array.IndexOf(volgorde, y.Soort)) return 1;
                if (Array.IndexOf(volgorde, x.Soort) < Array.IndexOf(volgorde, y.Soort)) return -1;
                if (x.Waarde > y.Waarde) return 1;
                if (x.Waarde < y.Waarde) return -1;
                return 0;
            }
        }


        public override string ToString()
        {
            string terug = "Aantal kaarten: " + AantalKaarten() + Environment.NewLine;
            foreach (Kaart kaart in kaarten)
            {
                terug += kaart.ToString() + Environment.NewLine;
            }
            return terug;
        }
        ////TODO        
        //•	Kaartspel vuurt een event af als de laatste kaart van een bepaald type wordt getrokken

        public void LaatsteKaartType(KaartSoort soort)
        {
            int teller = 0;
            foreach(Kaart k in kaarten)
            {
                if (k.Soort == soort)
                {
                    teller++;
                }
            }

            if (teller == 1)
            {
                throw new InvalidOperationException("");
            }
        }

        public Object Clone()
        {
            List<Kaart> newKaarten = new List<Kaart>();
            foreach (Kaart k in kaarten)
            {
                Kaart cloneK = (Kaart)k.Clone();
                newKaarten.Add(cloneK);
            }
            return newKaarten;
        }

        public Kaart this[int kaartIndex]
        {
            set
            {
                kaarten[kaartIndex] = value;
            }
            get
            {
                return kaarten[kaartIndex];
            }
        }

/*
        public Kaart this[KaartSoort soort, KaartWaarde waarde]
        {
            set 
            {
                Kaart kaart = ZoekKaart(waarde, soort);
                kaarten[kaarten.FindIndex(0, 1, kaart)] = value;
            }
            get
            {
                return ZoekKaart(waarde, soort);
            }
        }
  */


        public IEnumerator<Kaart> GetEnumerator()
        {
            foreach (Kaart kaart in kaarten)
            {
                yield return kaart;
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    } 



}
